#include "protocols/Ipv6.h"
#include "utilities/ReadablePacket.h"
#include "protocols/ProtocalCode.h"
#include "protocols/ProtocalPool.h"
#include "protocols/ShowableItem.h"
#include "utilities/utilities.h"

REGISTER_PROTOCOL(Ipv6)

QString Ipv6Header::getSummary() const 
{
	return QString("Src:%1 Dst:%2").arg(getSrcIp().toString()).arg(getDstIp().toString());
}

void Ipv6Header::toShowableItems(ShowableItem* root) const 
{
	HeaderFormat* header = (HeaderFormat*)mData;
	int pos = mPos;
	ShowableItem* tmp,*flag;

	ShowableItem* proto = createProtocalItem("IPV6 Header - Internet Protocal Datagram",pos,getHeaderLength());
	root->pushChild(proto);

	tmp = createItem("Version:",6,pos,0);
	proto->pushChild(tmp);

	QString bitstr,bitstr_tmp;
	bitstr = toBinaryString(header->mVer_Class,0,3);
	bitstr_tmp = toBinaryString(header->Class_FlowLabel,4,7);
	bitstr += bitstr_tmp;
	flag = createItemUnchange("Traffic Class:","%"+bitstr,QString(""),pos,1);
	proto->pushChild(flag);

	tmp = createFlagItem(bitstr,2,7,
		QString("=Differentiated Services Field"),pos,0);
	flag->pushChild(tmp);

	tmp = createFlagItem(bitstr,1,1,
		QString("=ECN-Capable Transport(ECT)"),pos,0);
	flag->pushChild(tmp);

	tmp = createFlagItem(bitstr,0,0,
		QString("=ECN-CE"),pos,0);
	flag->pushChild(tmp);

	bitstr = toBinaryString(header->Class_FlowLabel,0,3)+toBinaryString(header->FlowLabel_1,0,7)
		+toBinaryString(header->FlowLabel_2,0,7);

	tmp = createItem("Flow Label:","%"+bitstr,pos,4);
	proto->pushChild(tmp);


	tmp = createItem("Payload Length:",ntohs(header->mPlen),pos,2);
	proto->pushChild(tmp);

	tmp = createItem("Protocol:",toHexString(pointer(pos),1),pos,1);
	proto->pushChild(tmp);

	tmp = createItem("Hop Limit:",toHexString(pointer(pos),1),pos,1);
	proto->pushChild(tmp);

	tmp = createItem("Source Ip Address:",getSrcIp().toString(),pos,16);
	proto->pushChild(tmp);

	tmp = createItem("Dest Ip Address:",getDstIp().toString(),pos,16);
	proto->pushChild(tmp);
}

QString Ipv6Header::getSource() const 
{
	return getSrcIp().toString();
}

QString Ipv6Header::getDestination() const {
	return getDstIp().toString();
}

Ipv6::Ipv6() : Protocol(IPV6,QString("IPV6"))
{
}

void Ipv6::initProtoTable()
{
	memset(m_ProtolTable,0,sizeof(m_ProtolTable));
	m_ProtolTable[6] = ProtocolPool::getProtocal(TCP).get();
	m_ProtolTable[17] = ProtocolPool::getProtocal(UDP).get();
	m_ProtolTable[1] = ProtocolPool::getProtocal(ICMP).get();
	m_ProtolTable[2] = ProtocolPool::getProtocal(IGMP).get();
}

PacketHeader*
Ipv6::analyzeProc(ReadablePacket*packet,int low,int high,Protocol*& tip)
{
	Ipv6Header* header = new Ipv6Header(Ipv6_register.m_Instance,packet->getData(),low,high - low + 1);

	static bool inited = false;
	if (!inited) {
		initProtoTable();
		inited = true;
	}

	tip = m_ProtolTable[header->getTypeCode()];

	return header;
}

unsigned char Ipv6Header::getTypeCode() const {
	return ((HeaderFormat*)mData)->mType;
}